#pragma once 
#include<iostream>
#include<sys/socket.h>  //套接字函数（如：socket()...)
#include<netinet/in.h>  //定义网络地址结构（如 struct sockaddr_in）和协议常量（如 AF_INET、SOCK_STREAM）
#include<arpa/inet.h>   //IP 地址转换函数，字节序转换函数
#include<unistd.h> 
#include<cstring>
#include<string>
#include<assert.h>
#include"Log.hpp"   

//TCP服务端：1. socket() → 2. bind() → 3. listen() → 4. accept() → 5. write()/read() → 6. close() 
//TCP客户端：1. socket() → 2. connect() → 3. write()/read() → 4. close()

//客户端比较于服务端来说，只有3个不同：
//1. 客户端不用自己绑定端口，系统自己绑定，即没有bind函数
//2. 服务端在连接之前还要listen
//3. 客户端：connect   服务端：accept

//socket：直接得到两端的套接字
//connect：要服务端的所有信息      accept：得到客户端的所有信息     只有accept能得到新套接字（连接套接字）
//注意：write()/read()只需要一个套接字就行，而客户端还是用socket的那个套接字，而服务端必须用新套接字

//主机序列，网络字节序的转化永远是int在转（指uint32_t/uint64_t），所以只有port才会转，才要转

//使用说明：
//Sock listensock;
//listensock.Sock();  ...   

enum
{
    Socket_ERR=1,
    Bind_ERR,
    Listen_ERR,
    Accept_ERR,
    Close_ERR,
    Connect_ERR,
};

//适用于TCP的客户端和服务端
class Sock
{
    private:
        int _socket;
    public:
   
        void Socket()
        {
           _socket=socket(AF_INET, SOCK_STREAM, 0);
           if(_socket<0)
           {
                lg(Fatal,"socket error, _socket: %d。 %s",_socket,strerror(errno));
                exit(Socket_ERR);
           }
        }

        void Bind(uint16_t port)
        {
            struct sockaddr_in address;
            address.sin_addr.s_addr=INADDR_ANY; 
            address.sin_family=AF_INET;
            address.sin_port=htons(port);
            if(bind(_socket,(struct sockaddr*)&address,sizeof(address))<0)
            {
                lg(Fatal,"bind error, _socket: %d。 %s",_socket,strerror(errno));
                exit(Bind_ERR);
            }
        }

        //服务端
        void Listen()
        {
            if(listen(_socket,10))
            {
                lg(Fatal,"listen error, _socket: %d。 %s",_socket,strerror(errno));
                exit(Listen_ERR);
            }
        }

        //服务端专业函数，返回连接套接字
        //可以得到客户端的信息，虽然这些信息不能对读写有任何帮助，然后需要打印出客户信息
        int Accept(std::string* clientip,uint16_t* clientport)
        { 
            struct sockaddr_in tmp;
            memset(&tmp,0,sizeof(tmp));
            socklen_t len=sizeof(tmp);
            int newfd=accept(_socket,(sockaddr*)&tmp,&len);
            if(newfd<0)
            {
                lg(Fatal,"accept error, _socket: %d; newfd: %d 。%s",_socket,newfd,strerror(errno));
                exit(Accept_ERR);
            }
            char ipstr[64];
            *clientport=ntohs(tmp.sin_port);
            inet_ntop(AF_INET, &tmp, ipstr,sizeof(ipstr));
            *clientip=ipstr;
            
            return newfd;
        }

        //客户端
        //需要服务端的信息
        bool Connect(const std::string &serverip,const uint16_t &serverport)
        {
            sockaddr_in server;
            memset(&server,0,sizeof(server));
            server.sin_family=AF_INET;
            server.sin_port=htons(serverport);
            inet_pton(AF_INET,serverip.c_str(),&(server.sin_addr));
        

            socklen_t len=sizeof(server);
            if(connect(_socket,(sockaddr*)&server,len)<0)
            {
                std::cerr << "connect to " << serverip << ":" << serverport << " error" << std::endl;
                return false;                
            }
            return true;
        }

        // void Read(int socket,std::string *content)
        // {
        //     char buffer[SIZE];
        //     int n=read(socket,buffer,sizeof(buffer));
        //     if(n>0)
        //     {
        //         buffer[n]='\0';
        //         *content=buffer;
        //     }
        //     else if(n==0)  //断开了连接
        //     {
        //         std::cout<<"Connect Disconnect"<<std::endl;
        //     }
        //     else
        //     {
        //         lg(Fatal,"read error, socket: %d 。%s",socket,strerror(errno));
        //         exit(Read_ERR);
        //     }
        // }

        // void Write(int socket ,const std::string& content)
        // {
        //     if(content.empty())
        //     {
        //         std::cout<<"content is empty\n";
        //         return;
        //     }

        //     int n=write(socket,content.c_str(),content.size());

        //     if(n==0)  //断开了连接
        //     {
        //         std::cout<<"Connect Disconnect"<<std::endl;
        //     }
        //     else if(n<0)
        //     {
        //          lg(Fatal,"write error, socket: %d 。%s",socket,strerror(errno));
        //         exit(Write_ERR);
        //     }
        // }

        void Close()
        {
            if(close(_socket)<0)
            {
                exit(Close_ERR);
            }
        }

        int Fd()
        {
            return _socket;
        }
};